package xiaopiya.robot.handler.rss;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import xiaopiya.robot.IMessageSender;
import xiaopiya.robot.handler.rss.exception.RssContentException;
import xiaopiya.robot.handler.rss.tool.IRssBookingService;
import xiaopiya.robot.handler.rss.tool.RssChannelManager;
import xiaopiya.robot.handler.rss.tool.RssContent;

/**
 * @author Ray (ayufox@gmail.com)
 * @version 0.1
 */
public class JdbcRssBookingService extends JdbcDaoSupport implements
		IRssBookingService
{
	private final static Log LOG = LogFactory
			.getLog(JdbcRssBookingService.class);

	private String robot;

	private IMessageSender messageSender;

	private RssChannelManager rssChannelManager;

	public void setRobot(String robot)
	{
		this.robot = robot;
	}

	public void setMessageSender(IMessageSender messageSender)
	{
		this.messageSender = messageSender;
	}

	public void setRssChannelManager(RssChannelManager rssChannelManager)
	{
		this.rssChannelManager = rssChannelManager;
	}

	private Map<ChannelKey, Set<String>> bookers = new HashMap<ChannelKey, Set<String>>();

	public void init()
	{
		new Thread()
		{
			public void run()
			{
				initBookers();
			}
		}.start();
	}

	private void initBookers()
	{
		if (LOG.isInfoEnabled())
		{
			LOG.info("init[" + robot + "] bookings");
		}
		String sql = "select channel, childchannel, userid from xiaopiya_rssbooking where robotid = ?";
		List<ChannelBooking> list = getJdbcTemplate().query(sql, new Object[]
		{ this.robot }, new RowMapper()
		{

			public Object mapRow(ResultSet rs, int rowNum) throws SQLException
			{
				return new ChannelBooking(new ChannelKey(rs.getString(1), rs
						.getString(2)), rs.getString(3));
			}
		});

		for (ChannelBooking booking : list)
		{
			Set<String> bookings = getBookings(booking.getChannel());
			bookings.add(booking.getUserid());
			if (LOG.isInfoEnabled())
			{
				LOG.info("find booking[" + booking + "] robot[" + this.robot
						+ "]");
			}
			booking = null;
		}

		if (LOG.isInfoEnabled())
		{
			LOG.info("start [" + this.robot + "] booking success!");
		}
	}

	private Set<String> getBookings(ChannelKey channel)
	{
		Set<String> bookings = this.bookers.get(channel);
		if (bookings == null)
		{
			bookings = new LinkedHashSet<String>();
			this.bookers.put(channel, bookings);
		}
		return bookings;
	}

	public boolean book(String user, ChannelKey channel)
	{
		if (this.rssChannelManager.hasChannel(channel))
		{
			Set<String> bookings = getBookings(channel);
			if (!bookings.contains(user))
			{
				String sql = "insert into xiaopiya_rssbooking(robotid,channel, childchannel, userid) values (?, ?, ?, ?)";
				this.getJdbcTemplate().update(
						sql,
						new Object[]
						{ this.robot, channel.getChannel(),
								channel.getChildChannel(), user });
				bookings.add(user);
				if (LOG.isInfoEnabled())
				{
					LOG.info("add user[" + user + "] for channel[" + channel
							+ "] robot[" + this.robot + "]");
				}
			}

			return true;
		} else
		{
			return false;
		}
	}

	public boolean cancel(String user, ChannelKey channel)
	{
		if (this.rssChannelManager.hasChannel(channel))
		{
			Set<String> bookings = getBookings(channel);
			if (bookings.contains(user))
			{
				String sql = "delete from xiaopiya_rssbooking where robotid = ? and channel = ? and childchannel = ? and userid = ?";
				this.getJdbcTemplate().update(
						sql,
						new Object[]
						{ this.robot, channel.getChannel(),
								channel.getChildChannel(), user });
				bookings.remove(user);
				if (LOG.isInfoEnabled())
				{
					LOG.info("delete user[" + user + "] for channel[" + channel
							+ "] robot[" + this.robot + "]");
				}
			}

			return true;
		} else
		{
			return false;
		}
	}

	public void cancel(String user)
	{
		String sql = "delete from xiaopiya_rssbooking where robotid = ? and userid = ?";
		this.getJdbcTemplate().update(
				sql,
				new Object[]
				{ this.robot, user });
		if (LOG.isInfoEnabled())
		{
			LOG.info("cancel all booking for [" + user + "]");
		}
		for (ChannelKey key : this.bookers.keySet())
		{
			Set<String> users = this.bookers.get(key);
			if (users.contains(user))
			{
				users.remove(user);
				if (LOG.isInfoEnabled())
				{
					LOG.info("cancel booking[" + key + "] for user[" + user + "]");
				}
			}
			users = null;
		}
	}

	public void publish()
	{
		for (ChannelKey channel : this.bookers.keySet())
		{
			try
			{
				if (LOG.isInfoEnabled())
				{
					LOG.info("publish[" + channel + "]");
				}
				publish(channel);
			} catch (RssContentException e)
			{
				LOG.error("error when publish[" + channel + "]", e);
			}
		}
	}

	public String load(ChannelKey channel) throws RssContentException
	{
		RssContent content = this.rssChannelManager.getLastGet(channel);
		if (content == null)
		{
			return null;
		} else
		{
			return content.toString();
		}
	}

	private void publish(ChannelKey channel) throws RssContentException
	{
		Set<String> users = this.bookers.get(channel);
		if (users == null)
		{
			return;
		}
		if (LOG.isInfoEnabled())
		{
			LOG.info("Find user[" + users + "] for channel[" + channel
					+ "] robot[" + this.robot + "]");
		}
		RssContent content = this.rssChannelManager.getChangeFromLast(channel);
		String message = content.toString();
		if (message != null)
		{
			for (String user : users)
			{
				if (LOG.isInfoEnabled())
				{
					LOG.info("send rss message[" + message + "] to [" + user
							+ "] from [" + this.robot + "]");
				}
				this.messageSender.send(user, message);
			}
			users = null;
		}
	}

	public void userLogin(String users)
	{
	}
}